#!/usr/bin/env python
import re
import os
import os.path
import imp
import sys
import string


def load_module(mod, command_dict, builtins={}, overwrite=True):
    '''Parses a module's triggers and adds them to the dictionary
    suppplied (returns that dictionary).
    Params:
    modname - The module to parse for triggers.
    command_dict - The dictionary to add commands to.
    builtins - A dictionary of builtins to add.
    overwrite - Should duplicate triggers overwrite those already in
                the dictionary? (Default: True)
    '''
    try:
        #Give every module a copy of the registry.
        if builtins:
            for k in builtins.keys():
                mod.__builtins__[k] = builtins[k]

        if hasattr(mod, "SETUP"):
            mod.SETUP()

        for k in mod.TRIGGERS.keys():

            cleankey = re.sub('[^a-z]', '', k.lower().strip())

            if cleankey not in command_dict.keys() or overwrite:
                command_dict[cleankey] = mod.TRIGGERS[k]
            else:
                print("Command %s already in dictionary." % (k))
    except AttributeError:
        print("Module %s has no triggers." % (mod.__name__))

    _possible_commands = gen_possible_commands(command_dict)

    return command_dict


def add_to_path(newpath):
    '''Adds the given path to the system path.'''
    if newpath not in sys.path:
        sys.path.append(newpath)


def get_py_modules(directory):
    '''Returns a list of python modules in the given directory.'''

    add_to_path(directory)  #Add the path to the system path.

    try:
        pluginfiles = [f[:-3] for f in os.listdir(directory) if f.endswith(".py")]
    except OSError:
        print("%s doesn't exist or isn't readable by butler" % (pluginpath))
        return []
    return pluginfiles


def load_plugins(pluginfiles):
    '''Loads all of the modules in the given directory as plugins. All
    modules must have a .py extension.

    Paramaters:
        pluginfiles - A list of modules to import.

    Returns:
        A list of imported modules.
    '''

    #Import the modules from the given list of names.
    imported_modules = []
    for f in pluginfiles:
        try:
            imported_modules.append(__import__(f))
        except Exception, e:
            print("Unable to import: %s" % (f))
            print("\t%s" % (e) )

    return imported_modules

def do_nothing(*args, **kwargs):
    '''Does nothing, but can be passed any number of arguments'''
    return


def init_plugins(folderlist, builtins_append=None):
    '''Returns a dictionary in the form "command":<callable>
    These are grabbed from the plugins from the list supplied in
    folderlist.

    If all of the new plugins should have items appended to their
    builtins then those should be added to the builtins_append dict.
    Where the key is the name of the builtin, and the value is the
    callable. All items in builtins_append should be callable.  To
    remove items from a builtins just set the items not wanted to a
    variable argument callable that does nothing, one is provided in
    this module it is aptly named "do_nothing".

    '''
    cd = {}
    for f in folderlist:
        pluginfiles = get_py_modules(f)  #Create a list of possible plugin files from the path given.

        modules = load_plugins(pluginfiles)  #Import each file as a module.

        #Perform loading for each module.
        for mod in modules:
            cd = load_module(mod, cd, builtins_append)

    return cd


def gen_possible_commands(command_dictionary):
    '''Sets up a sorted list of commands from a command dictionary.'''
    #Set up a list of potential commands for quick reference.
    possible_commands = command_dictionary.keys()
    possible_commands = sorted(possible_commands)
    possible_commands.reverse()  #Most specific command first :)
    return possible_commands